import datetime

from flask import request
from flask_restful import Resource, reqparse, fields, marshal, abort
from flask_restful.fields import Raw
from sqlalchemy import or_, and_

from main.apis.api_constant import HTTP_OK, HTTP_CREATE_OK
from main.apis.user.utils import ordinary_login_required, get_now_time
from main.ext import cache, db
from main.models.goods.goods_model import Goods
from main.models.user.user_model import CartModel, OrderModel, NOT_PAID, NOT_VALID, VALID


class GoodName(Raw):
    """
      如果希望返回的商品标志是商品名，则需要自定义一个Raw子类来完成
    """

    def format(self, value):
        good = Goods.query.get(value)
        return good.g_name


cart_goods_fields = {  # 购物车展示的信息
    # 'user_id': fields.String(attribute='c_user_id'),  # 每个用户只能查自己的购物车，所以user_id不需要展示出来
    # 'good_id': fields.String(attribute='c_goods_id'),  # 可以仅提供商品id给前端
    'good_name': GoodName(attribute='c_goods_id'),  # 也可以提供商品名称给前端
    'good_count': fields.Integer(attribute='c_goods_count'),
    'is_selected': fields.Boolean(attribute='c_is_selected')
}

add_cart_goods_fields_data = {  # 向购物车内添加商品成功后返回的信息
    'status': fields.Integer,
    'msg': fields.String,
    'data': fields.Nested(cart_goods_fields)
}

all_cart_goods_fields_data = {  # 查询用户购物车内所有的商品
    'status': fields.Integer,
    'msg': fields.String,
    'data': fields.List(fields.Nested(cart_goods_fields))
}

parser = reqparse.RequestParser()
parser.add_argument('g_id', type=int, required=True, help='请输入商品 id')
parser.add_argument('g_count', type=int)  # 有默认值，可以不填
parser.add_argument('is_selected', type=bool)


class CartResource(Resource):
    @ordinary_login_required
    def get(self):
        token = request.args.get('token')
        user_id = cache.get(token)
        cart_goods = CartModel.query.filter(CartModel.c_user_id == user_id).all()
        data = {
            'status': HTTP_OK,
            'msg': '购物车信息获取成功',
            'data': cart_goods
        }

        return marshal(data, all_cart_goods_fields_data)

    @ordinary_login_required
    def post(self):
        token = request.args.get('token')
        user_id = cache.get(token)
        args = parser.parse_args()
        g_id = args.get('g_id')
        g_count = args.get('g_count')

        # 对库存商品的数量进行修正，回收所有的未付款且无效的订单和所有未付款有效但超时的订单的商品的数量
        orders = OrderModel.query.filter(or_(
            and_(
                OrderModel.o_status == NOT_PAID,
                OrderModel.o_valid == NOT_VALID
            ),
            and_(
                OrderModel.o_status == NOT_PAID,
                OrderModel.o_valid == VALID,
                # 生成订单后，到跳转到支付宝支付页面的时间肯定大于支付宝的支付有效期，所以判断订单有效期应该减去一个稍大于支付宝支付有效期的数字
                OrderModel.o_time < get_now_time()[0] - datetime.timedelta(minutes=21)  # 支付宝有效期为20分钟
            )
        )).all()
        for order in orders:
            for good in order.goods:
                good.goods.g_count += good.o_goods_count  # 库存商品数量加上无效订单中商品数量
                good.o_goods_count = 0  # 无效订单中商品数量归零
        # db.session.commit()

        # 判断商品是否存在
        good_exits = Goods.query.get(g_id)
        if not good_exits:
            abort(404, error='商品不存在')
        # 判断购物车中是否已存在此商品
        good = CartModel.query.filter(CartModel.c_user_id == user_id, CartModel.c_goods_id == g_id).first()
        g_count = 1 if not g_count else g_count
        print(good_exits.g_count, g_count)
        if not good:
            if good_exits.g_count < g_count:
                abort(403, error=f'商品库存不足：您选购的商品 `{good_exits.g_name}` 库存有 `{good_exits.g_count}`件，\
你要增加的数量 `{g_count}` 超出剩余库存数量')
            cart = CartModel()
            cart.c_user_id = user_id
            cart.c_goods_id = g_id
            cart.c_goods_count = g_count
            cart.save()
            data = {
                'status': HTTP_CREATE_OK,
                'msg': '已添加进购物车',
                'data': cart
            }

            return marshal(data, add_cart_goods_fields_data)
        count = good.c_goods_count + g_count
        if good_exits.g_count < count:
            abort(403, error=f'商品库存不足：您的购物车中已有此商品 `{good_exits.g_name}` -> `{good.c_goods_count}` 件，\
库存有 `{good_exits.g_count}`件，你要增加的数量 `{g_count}` 超出剩余库存数量')
        good.c_goods_count = count
        good.save()
        data = {
            'status': HTTP_CREATE_OK,
            'msg': '购物车中已存在此商品，选购数量已与购物车原数量相加',
            'data': good
        }

        return marshal(data, add_cart_goods_fields_data)
